
public final class GameBoardTool {

	public static final int EMPTY = 0;
	public static final int PLAYER1 = 1;
	public static final int PLAYER2 = 2;

	private static final float EmptyFieldfactor = (float) 0.1;


	public GameBoardTool() {

	}

	
	public void printValues(GameBoard g, int player ) {
		
		for (int i =1 ; i <= g.columns ; i++) {
			
			System.out.println("Value of " + i +" " + this.columnValue(g, i, player,1 ));
			
		}
		
	}


	public float columnValue(GameBoard g, int col, int player, int minimax) {

		float value = 0;

		if (columnFull(g, col)) return 0;

		float down = evalDown(g, col, player);
		if (countDown(g, col,player) >= 3) return winnerValue(player) * minimax; // winning column
		else value+= down;

		if ( countSidewards(g, col, player) >= 3) return winnerValue(player)  * minimax; // winning column
		else value+= evalSidewards(g, col, player);

		if ( countLeftDown(g, col, player) == 3) return winnerValue(player) * minimax; // winning column
		else value+= evalLeftDown(g, col,player);

		if ( countRightDown(g, col, player) == 3) return winnerValue(player) * minimax; // winning column
		else value+= evalRightDown(g, col,player);

		if (value != 0) value = value/10;

//		if (player == 2) return value * minimax;
//		else 
			return  value * minimax;

	}
	
	private int winnerValue(int player) {
		if ( player == PLAYER1 ) return -1;
		else  return 1;
	}


	public boolean columnFull(GameBoard g, int col) {
		return(g.coinsInColumn[col-1] == g.rows);
	}


	public int countDown(GameBoard g, int col, int player) {

		if (columnFull(g, col) || columnEmpty(g, col) ) return 0; 
		else {
			int count = 0;
			int i = g.coinsInColumn[col-1] -1 ;

			while ( i >= 0 && g.board[col-1][i] == player ) {
				count++;
				i--;		
			}	
			return count;
		}
	}	


	public boolean isWinningColumn(GameBoard g , int col, int player) {

		return  (countDown(g, col, player) == 3) || 
				(countSidewards(g, col, player) >= 3) || 
				(countLeftDown(g, col, player) + (countRightUp(g, col, player) ) >= 3 ) || 
				(countRightDown(g, col, player) + (countLeftUp(g, col, player) ) >= 3 ) ;
	}

	// returns winning column if exists, else 0
	public int winningColumn (GameBoard g , int player) {

		for (int i = 1 ; i <= g.columns ; i++) 
		{
			if ( !columnFull(g,i) && isWinningColumn(g, i, player)) return i;
		} 

		return 0;
	}

	private float evalDown(GameBoard g, int col, int player) {		

		int count = countDown(g, col, player) + 1;	
		int onTop = (g.rows - getCoinsInColumn(g, col)) -1 ; // number of free fields above

		if (count + onTop < 4) return 0; // no possibility of winning

		else // 
			return count + (onTop * EmptyFieldfactor); 
	}


	private float evalLeft(GameBoard g, int col, int player) {	

		int count = countLeft(g, col, player);
		int leftFree = countLeft(g, col-count, EMPTY);

		return count + (leftFree * EmptyFieldfactor);

	}

	private float evalRight(GameBoard g, int col, int player) {	

		int count = countRight(g, col, player);
		int rightFree = countRight(g, col+count, EMPTY);

		return count + (rightFree * EmptyFieldfactor);
	}

	private float evalSidewards(GameBoard g, int col, int player) {

		float bonus = 1;
		int row = getCoinsInColumn(g, col);
		int countLeft = countLeft(g, col, player);
		int freeLeft = countLeft(g, col - countLeft, row, EMPTY);
		int countRight = countRight(g, col, player);
		int freeRight = countRight(g, col + countRight, row, EMPTY);

		if (countLeft + countRight + 1 + freeLeft + freeRight < 4 ) return 0;

		if (freeRight > 0 && freeLeft > 0 ) bonus = (float) 1.1; //empty fileds in both direction better
		
		return countLeft + countRight + 1 + ( (freeLeft + freeRight) * EmptyFieldfactor * bonus);
	}

	private float evalLeftDown (GameBoard g, int col, int player) {

		float bonus = 1;
		int i = col;
		int j = getCoinsInColumn(g, col) + 1;

		int countDown = 0; 
		int countUp = 0;
		int freeBelow = 0; 
		int freeAbove = 0;

		while (pathLeftDown(i, j)) {

			if ( g.board[i-2][j-2] == player ) countDown++;
			else if (g.board[i-2][j-2] == EMPTY) freeBelow++;	
			i--; j--;
		}

		i = col;
		j = getCoinsInColumn(g, col) + 1;

		while (pathRightUp(g, i, j)) {
			if ( g.board[i][j] == player ) countUp++;
			else if (g.board[i][j] == EMPTY) freeAbove++;	
			i++; j++;
		}


		if (countDown + countUp + freeBelow + freeAbove + 1 < 4 ) return 0;
		
		if (freeBelow > 0 && freeAbove > 0 ) bonus = (float) 1.1; //empty fields in both direction better

		return (countDown + countUp + 1 + (freeBelow + freeAbove) * EmptyFieldfactor * bonus);

	}

	private float evalRightDown(GameBoard g, int col, int player) {		

		float bonus = 1;
		int i = col;
		int j = getCoinsInColumn(g, col) + 1;

		int countDown = 0; 
		int countUp = 0;
		int freeBelow = 0; 
		int freeAbove = 0;

		while (pathRightDown(g, i, j)) {

			if ( g.board[i][j-2] == player ) countDown++;
			else if (g.board[i][j-2] == EMPTY) freeBelow++;	
			i++; j--;
		}

		i = col;
		j = getCoinsInColumn(g, col) + 1;

		while (pathLeftUp(g, i, j)) {
			if ( g.board[i-2][j] == player ) countUp++;
			else if (g.board[i-2][j] == EMPTY) freeAbove++;	
			i--; j++;
		}


		if (countDown + countUp + freeBelow + freeAbove + 1 < 4 ) return 0;
		
		if (freeBelow > 0 && freeAbove > 0 ) bonus = (float) 1.1; //empty fields in both direction better

		return (countDown + countUp + 1 + (freeBelow + freeAbove) * EmptyFieldfactor * bonus);

	}




	private int countLeft(GameBoard g, int col, int player) {

		if (columnFull(g, col) ) return 0;
		return countLeft(g, col, g.coinsInColumn[col-1], player);
	}

	private int countLeft(GameBoard g, int col, int row, int player) {

		int count = 0;
		int i = col-1;
		int j = row;

		while ( i > 0 && g.board[i-1][j] == player ) {
			count++;
			i--;		
		}
		return count;
	}

	private int countRight(GameBoard g, int col, int row, int player) {

		int count = 0;
		int i = col;
		int j = row;

		// count on right side
		while ( i < g.columns && g.board[i][j] == player ) {
			count++;
			i++;	
		}

		return count;
	}

	private int countRight (GameBoard g,int col, int player) {

		if (columnFull(g, col) ) return 0;
		return countRight(g, col, g.coinsInColumn[col-1], player);

	}

	private int countSidewards(GameBoard g,int col, int player) {

		return countLeft(g, col, player) + countRight(g, col, player);
	}


	private int countLeftDown(GameBoard g,int col, int player) {

		if (col <= 1) return 0; 

		return countLeftDown(g, col, getCoinsInColumn(g, col) + 1, player);
	}

	private int countLeftDown(GameBoard g, int col, int row, int player) {

		if (col <= 1 || row <= 1) return 0; 


		else {

			int count = 0;
			int i = col-1;
			int j = row-1;

			while ( i > 0 && j> 0 && g.board[i-1][j-1] == player ) {

				count++;
				j--;
				i--;		
			}

			return count;
		}
	}

	private int countLeftUp(GameBoard g, int col, int player) {

		if (columnFull(g, col) || col == 1 ) return 0; 

		else {
			int count = 0;
			int j = g.coinsInColumn[col-1] + 1;
			int i = col-2;

			while ( i >= 0 && j < g.rows && g.board[i][j] == player ) {

				count++;
				j++;
				i--;		
			}

			return count;
		}
	}

	private int countRightUp(GameBoard g, int col, int player) {

		if (columnFull(g,col) || col == g.columns ) return 0; 

		else {
			int count = 0;
			int j = g.coinsInColumn[col-1] + 1;
			int i = col + 1;

			while ( i <= g.columns && j < g.rows && g.board[i-1][j] == player ) {

				count++;
				j++;
				i++;		
			}

			return count;
		}
	}

	private int countRightDown(GameBoard g, int col, int player) {

		if (columnFull(g, col) || columnEmpty(g, col) || col == g.columns ) return 0; 

		else {
			int count = 0;
			int i = g. coinsInColumn[col-1] -1;
			int j = col;

			while ( i >= 0 && j< g.columns && g.board[j][i] == player ) {

				count++;
				j++;
				i--;		
			}

			return count;
		}
	}


	private boolean pathDown(int col, int row) {
		return (row - 1 > 0); 
	}

	private boolean pathUp(GameBoard g, int col, int row) {
		return (g.rows - row > 0);
	}

	private boolean pathLeft(int col, int row) {
		return (col - 1 > 0);
	}

	private boolean pathRight(GameBoard g,int col, int row) {
		return (col + 1 <= g.columns);
	}

	private boolean pathLeftDown(int col, int row) {
		return (pathLeft(col,row) && pathDown(col,row));
	}

	private boolean pathRightDown(GameBoard g, int col, int row) {
		return (pathRight(g, col,row) && pathDown(col,row));
	}

	private  boolean pathLeftUp(GameBoard g, int col, int row) {
		return (pathLeft(col,row) && pathUp(g, col,row));
	}

	private boolean pathRightUp(GameBoard g, int col, int row) {
		return (pathRight(g,col,row) && pathUp(g, col,row));
	}

	private int getCoinsInColumn(GameBoard g, int col) {
		return g.coinsInColumn[col-1];
	}

	private boolean columnEmpty(GameBoard g, int col) {
		return(g.coinsInColumn[col-1] == 0);
	}


}


